package com.lanou.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.lanou.entity.*;
import com.lanou.mapper.TbItemDescMapper;
import com.lanou.mapper.TbItemMapper;
import com.lanou.mapper.TbItemParamItemMapper;
import com.lanou.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by QuChao on 2018/11/19
 */
@Service
public class ItemServiceImpl implements ItemService {
    @Autowired
    private TbItemMapper tbItemMapper;

    @Autowired
    private TbItemDescMapper tbItemDescMapper;

    @Autowired
    private TbItemParamItemMapper tbItemParamItemMapper;

    @Autowired
    private JedisPool jedisPool;


    /**
     * 在Redis中添加数据，需要查询数据库，数据库数据量较大时，会查询很久
     * 使用了分页查询、多线程，提高查询速度
     */
    @Override
    public void addCache() {

        /*  ------------  查询tb_item表，将数据插入Redis  ---------------*/
        TbItemExample tbItemExample = new TbItemExample();
        long count = tbItemMapper.countByExample(tbItemExample);

        int rows = 50;
        int threadCount = (int) (count / rows) + 1;
        for (int i = 0; i <= threadCount; i++) {
            int startPage = i * rows;
            new Thread(new ItemSetRedis(tbItemMapper, jedisPool, startPage, rows)).start();
            System.out.println("i的值：" + i);
        }

        /*  --------------- ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑  -----------------------*/

        /*  --------------  查询tb_item_desc表，将数据插入Redis  ----------*/

        TbItemDescExample tbItemDescExample = new TbItemDescExample();
        count = tbItemDescMapper.countByExample(tbItemDescExample);
        threadCount = (int) (count / rows) + 1;
        for (int i = 0; i < threadCount; i++) {
            int startPage = i * rows;
            new Thread(new ItemDescRedis(tbItemDescMapper, jedisPool, startPage, rows)).start();
            System.out.println("i的值：" + i);
        }

        /*  --------------- ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑  -----------------------*/

        /*  -----------  查询tb_item_Param_item表，将数据插入Redis  ----------*/

        TbItemParamItemExample tbItemParamItemExample = new TbItemParamItemExample();
        count = tbItemParamItemMapper.countByExample(tbItemParamItemExample);

        threadCount = (int) (count / rows) + 1;
        for (int i = 0; i < threadCount; i++) {
            int startPage = i * rows;
            new Thread(new ItemParmItemSetRedis(tbItemParamItemMapper, jedisPool, startPage, rows)).start();
            System.out.println("i的值：" + i);
        }

        /*  --------------- ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑  -----------------------*/
    }

    /**
     * @param id itemID
     * @return 一个Map集合，存放的是三个表所对应的对象
     */
    @Override
    public Map<String, Object> getCacheById(Long id) {
        Map<String, Object> map = new HashMap<>();
        Jedis jedis = jedisPool.getResource();
        String descString = jedis.get("desc" + id);
        String itemString = jedis.get("item" + id);
        String paramItemString = jedis.get("paramItem" + id);

        TbItem tbItem = JSON.parseObject(itemString, new TypeReference<TbItem>() {
        });
        TbItemDesc tbItemDesc = JSON.parseObject(descString, new TypeReference<TbItemDesc>() {
        });
        TbItemParamItem tbItemParamItem = JSON.parseObject(paramItemString, new TypeReference<TbItemParamItem>() {
        });

        map.put("tbItem", tbItem);
        map.put("itemDesc", tbItemDesc);
        map.put("itemParamItem", tbItemParamItem);

        return map;
    }

    /**
     * @param id itemID
     * @return 是否更新成功的状态
     */
    @Override
    public boolean updataById(Long id) {
        return insertOrUpdataById(id);
    }

    /**
     * @param id 删除使用的主键ID
     * @return 如果删除成功返回true，失败返回false
     */
    @Override
    public boolean deleteById(Long id) {
        Jedis jedis = jedisPool.getResource();

        /*
         * 手动事务
         * 先提取Redis中的数据，再删除，如果提取的事务是空，返回false
         * 如果删除成功，直接返回true；如果删除失败，在Redis中重新更新一遍数据，返回false
         * */
        String itemString = jedis.get("item" + id);
        String descString = jedis.get("desc" + id);
        String paramItemString = jedis.get("paramItem" + id);

        if (itemString == null || descString == null || paramItemString == null) {
            jedis.close();
            return false;
        } else {
            Long delRS = jedis.del("item" + id, "desc" + id, "paramItem" + id);

            if (delRS == 3) {
                jedis.close();
                return true;
            } else {
                jedis.set("item" + id, itemString);
                jedis.set("desc" + id, descString);
                jedis.set("paramItem" + id, paramItemString);
                jedis.close();
                return false;
            }
        }
    }

    @Override
    public TbItem getItemInfoById(Long id) {

        Jedis jedis = jedisPool.getResource();
        String itemString = jedis.get("item" + id);
        return JSON.parseObject(itemString, new TypeReference<TbItem>() {
        });
    }

    @Override
    public TbItemDesc getItemDescInfoById(Long id) {
        Jedis jedis = jedisPool.getResource();
        String descString = jedis.get("desc" + id);
        return JSON.parseObject(descString, new TypeReference<TbItemDesc>() {
        });
    }

    @Override
    public TbItemParamItem getItemParamItemInfoById(Long id) {

        Jedis jedis = jedisPool.getResource();
        String paramItemString = jedis.get("paramItem" + id);
        return JSON.parseObject(paramItemString, new TypeReference<TbItemParamItem>() {
        });
    }

    /**
     * 提取的在Redis中进行插入或者更新的方法
     *
     * @param id itemID
     * @return 操作是否成功的状态
     */
    private boolean insertOrUpdataById(Long id) {
        TbItemParamItemExample tbItemParamItemExample = new TbItemParamItemExample();
        tbItemParamItemExample.createCriteria().andItemIdEqualTo(id);

        TbItem tbItem = tbItemMapper.selectByPrimaryKey(id);
        TbItemDesc tbItemDesc = tbItemDescMapper.selectByPrimaryKey(id);
        List<TbItemParamItem> tbItemParamItemList = tbItemParamItemMapper.selectByExampleWithBLOBs(tbItemParamItemExample);


        if (tbItemParamItemList.size() == 1) {
            Jedis jedis = jedisPool.getResource();

            String itemString = JSON.toJSONString(tbItem, SerializerFeature.WriteClassName);
            String itemDescString = JSON.toJSONString(tbItemDesc, SerializerFeature.WriteClassName);
            String tbItemParamItemString = JSON.toJSONString(tbItemParamItemList.get(0), SerializerFeature.WriteClassName);

            jedis.set("item" + id, itemString);
            jedis.set("desc" + id, itemDescString);
            jedis.set("paramItem" + id, tbItemParamItemString);

            jedis.close();

            return true;
        } else {
            return false;
        }
    }
}
